/*
Copyright  2018 Blockchain Technology and Application Joint Lab, Fintech Research Center of ISCAS.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
 */
import React, {Component, PropTypes} from 'react';
import {browserHistory} from 'react-router';
import {Meteor} from 'meteor/meteor';
import FlatButton from 'material-ui/FlatButton';
import RaisedButton from 'material-ui/RaisedButton';
import TextField from 'material-ui/TextField';
import {Stepper, Step, StepLabel, StepContent} from 'material-ui/Stepper';
import {RadioButton, RadioButtonGroup} from 'material-ui/RadioButton';
import Paper from 'material-ui/Paper';
import SvgIconCheck from 'material-ui/svg-icons/action/check-circle';
import SvgIconErr from 'material-ui/svg-icons/alert/error';
import SvgIconBack from 'material-ui/svg-icons/navigation/chevron-left';
import Divider from 'material-ui/Divider';
import DropZone from 'react-dropzone';
import { X509, KEYUTIL } from 'jsrsasign';
import baseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import {green400, blue300, red500, grey900} from 'material-ui/styles/colors';
import db from "../DBStore/db";
import faker from 'faker/locale/zh_CN';
import {
    CreateKeyPair,
    GenCertificateWithPemPrvKey,
    CreatePrvKeyByImport
} from '../api/cryptoHelper'
import {Buffer} from "buffer";

export default class AccountRegister extends Component {
    constructor(props) {
        super(props);
        this.state = {

            // For Join stepper
            new_not_import:true,
            finished: false,
            step_index: 0,
            result:false,
            res_fail:'',
            res_success:'',

            // For Join new info 
            new_pass1: '',
            new_pass1_err: '',
            new_pass2: '',
            new_pass2_err: '',
            new_name: '',
            default_name:'',
            new_name_err: '',
            new_phone: '',
            default_phone:'',
            new_phone_err: '',
            new_email: '',
            default_email:'',
            new_email_err: '',
            new_address: '',
            default_address:'',
            new_address_err: '',
            new_unit: '',
            default_unit: '',
            new_unit_err: '',

            // For Join import info
            import_prv_key_b2s:'',
            import_prv_key_file_name: '',
            import_cert_b2s:'',
            import_cert_file_name: '',
        };
    }

    getChildContext() {
        return {muiTheme: getMuiTheme(baseTheme)};
    }


    handleRegister() {
        const {new_name, new_phone, new_email, new_address, new_unit, new_pass1, new_not_import,
            result, res_fail, res_success, import_prv_key_b2s, import_cert_b2s
        } = this.state;
        const info = {
            name: new_name,
            phone: new_phone,
            email: new_email,
            address: new_address,
            unit: new_unit,
            createdAt: new Date(),
            isAdmin: false,
            account_address: 'none',
            status:true,
            avatar:faker.image.avatar(),
        };
        let  prv_key_pem_encrypted = '', user_certificate_pem = '';

        if(new_not_import) {
            prv_key_pem_encrypted = CreateKeyPair(new_pass1, new_phone);
            user_certificate_pem = GenCertificateWithPemPrvKey(new_pass1, info, prv_key_pem_encrypted);
        }else {
            prv_key_pem_encrypted = new Buffer(import_prv_key_b2s, 'hex').toString('utf-8');;

            user_certificate_pem = new Buffer(import_cert_b2s, 'hex').toString('utf-8');

            let obj;
            try {
                obj = KEYUTIL.getKey(prv_key_pem_encrypted)
                console.log(obj)
                if (obj) {
                    if (obj.pubKeyHex == undefined) {
                        const cert = new X509();
                        cert.readCertPEM(user_certificate_pem);
                        if (cert) {
                            obj.pubKeyHex = cert.getPublicKeyHex();
                            console.log(obj.pubKeyHex)
                            prv_key_pem_encrypted = KEYUTIL.getPEM(obj, 'PKCS8PRV', new_phone)
                            console.log(prv_key_pem_encrypted)
                        } else {
                            this.setState({result: true, res_fail: "证书格式错误请联系管理员", res_success: ''});
                            return;
                        }
                    }
                } else {
                    this.setState({result: true, res_fail: "私钥格式错误请联系管理员", res_success: ''});
                    return
                }
            }catch (e){
                if(e == 'not supported argument'){
                    console.log("该密钥有密码")
                }
            }
        }
        info.prv_key_pem_encrypted = prv_key_pem_encrypted;
        info.user_certificate_pem = user_certificate_pem;
        db.table('users').where({phone: new_phone}).first().then((res) => {
            if (!res) {
                db.table('users').add(info).then((id) => {
                    this.setState({result: true, res_fail: '', res_success:'用户注册成功！'});
                })
            } else {
                this.setState({result: true, res_fail: "该手机号已被注册！", res_success:''});
            }
        }).catch((reason) => {
            console.log(reason)
            this.setState({result: true, res_fail: reason, res_success:''});
        });
    }

    handleNext() {
        const {
            step_index, finished
        } = this.state;

        this.setState({
            step_index: step_index + 1,
            finished: step_index >= 2,
        });
        if(step_index == 2)
            this.handleRegister();
    }

    handlePrev() {
        const {step_index} = this.state;
        if (step_index > 0) {
            this.setState({step_index: step_index - 1});
        }
    }

    onDropPrvKeyFile(acceptedFiles, failedFiles) {
        if (acceptedFiles.length == 0)
            throw new Error('Import prvKey file failed');
        const prv_key_file = acceptedFiles[0];
        this.setState({import_prv_key_file_name: prv_key_file.name});
        let fr = new FileReader();
        fr.onload = () => {
            const b = new Buffer(fr.result);
            const b_s = b.toString('hex');
            this.setState({import_prv_key_b2s: b_s});
        }
        fr.onerror = () => {
            console.log('Error: import reading prvkey file failed')
        }
        fr.readAsArrayBuffer(prv_key_file);
    }

    onDropCertFile(acceptedFiles, failedFiles) {
        if (acceptedFiles.length == 0)
            throw new Error('Import cert file failed');
        const cert_file = acceptedFiles[0];
        this.setState({import_cert_file_name: cert_file.name});
        let fr = new FileReader();
        fr.onload = () => {
            const b = new Buffer(fr.result);
            const b_s = b.toString('hex');
            this.setState({import_cert_b2s: b_s});
        }
        fr.onerror = () => {
            console.log('Error: import reading prvkey file failed')
        }
        fr.readAsArrayBuffer(cert_file);
    }

    renderStepActions(step) {
        const {step_index,new_not_import,
            new_name, new_name_err,
            new_phone, new_phone_err,
            new_email, new_email_err,
            new_address, new_address_err,
            new_unit, new_unit_err,
            new_pass1, new_pass1_err,
            new_pass2, new_pass2_err,
            import_prv_key_b2s, import_cert_b2s
        } = this.state;
        let can_next = false;
        if(step == 0){
            can_next = new_name_err == ''&& new_phone_err == '' &&
                new_email_err == '' && new_address_err == '' &&
                new_unit_err == '' && new_name != '' &&
                new_phone != '' && new_email != '' &&
                new_address != '' && new_unit != '';

        }else if(step == 1) {
            can_next = new_not_import? new_pass1 == new_pass2 &&
                new_pass1 != '' &&  new_pass1_err == '' && new_pass2_err == '': import_prv_key_b2s != '' && import_cert_b2s != '';
        }else{
            can_next = true;
        }


        return (
            <div style={{margin: '12px 0'}}>
                <RaisedButton
                    label={step_index === 2 ? '确认注册' : '下一步'}
                    disableTouchRipple={true}
                    disableFocusRipple={true}
                    disabled={!can_next}
                    primary={can_next}
                    onClick={

                        this.handleNext.bind(this)
                    }
                    style={{marginRight: 12}}
                />
                {step > 0 && (
                    <FlatButton
                        label="上一步"
                        disabled={step_index === 0}
                        disableTouchRipple={true}
                        disableFocusRipple={true}
                        onClick={this.handlePrev.bind(this)}
                    />
                )}
            </div>
        );
    }


    render() {
        const {
            finished, step_index,new_not_import,
            new_name, default_name, new_name_err,
            new_phone, default_phone, new_phone_err,
            new_email, default_email, new_email_err,
            new_address, default_address, new_address_err,
            new_unit, default_unit, new_unit_err,
            new_pass1, new_pass1_err,
            new_pass2, new_pass2_err,
            import_prv_key_file_name,import_prv_key_b2s,
            import_cert_file_name,import_cert_b2s,
            result, res_fail, res_success
        } = this.state;
        const import_prvkey_border_style = import_prv_key_file_name != '' ? '1px dashed #46c121' : '1px dashed'
        const import_cert_border_style = import_cert_file_name != '' ? '1px dashed #46c121' : '1px dashed'
        if(res_fail!='' || res_success !=''){
            setTimeout(function () {
              if(res_success != ''){
                  browserHistory.push('/login');
              }else {
                  this.setState({result:false, res_success:'', res_fail:'', step_index:0, finished:false})
              }
            }.bind(this),2000)
        }
        return (
            <div style={{maxWidth: 450, maxHeight: 780, margin: 'auto'}}>
                <Paper zDepth={5} style={{width: '90%', height: 'auto', top: '10%', left: '5%', right: '5%',position: 'absolute'}}>
                    <h1 style={{fontWeight: 'normal', fontFamily: 'sans-serif',}}>
                        <FlatButton
                            label='返回登录'
                            icon={<SvgIconBack/>}
                            onClick={(e) => {
                                browserHistory.push('/login')
                            }}
                        />
                        <div id='register_title'>注册</div>
                    </h1>


                    <Divider style={{marginTop: '-1%', marginLeft: '1%',marginRight: '1%', border: '0.02px dashed'}}/>
                    {result &&
                    <Paper zDepth={4} style={{width: '60%', marginLeft: '20%', marginTop: 12, wordBreak: 'break-all'}}>
                        {
                            res_fail==''?
                                <SvgIconCheck style={{color: green400, marginLeft: 5, marginTop: 2}}/> :
                                <SvgIconErr style={{color: red500, marginLeft: 5, marginTop: 2}}/>
                        }
                        <div id='new_or_import_result'>
                            {
                                res_fail || res_success
                            }
                        </div>
                    </Paper>
                    }
                    <Stepper activeStep={step_index} orientation='vertical'
                             style={{marginBottom: '1%', marginLeft: '1%', marginRight:'1%'}}>
                        <Step>
                            <StepLabel>用户信息填写</StepLabel>
                            <StepContent>
                                <TextField
                                    hintText='输入姓名'
                                    errorText={new_name_err}
                                    floatingLabelText='姓名'
                                    defaultValue={default_name}
                                    floatingLabelStyle={{color: blue300}}
                                    fullWidth={true}
                                    onChange={(e, newValue) => {
                                        const name = newValue;
                                        if (name === '')
                                            this.setState({new_name: name, new_name_err: '姓名不可为空'});
                                        else
                                            this.setState({new_name: name, default_name: name, new_name_err: ''});
                                    }}
                                />
                                <TextField
                                    hintText='输入手机号，将作为您的用户名'
                                    errorText={new_phone_err}
                                    floatingLabelText='手机'
                                    defaultValue={default_phone}
                                    floatingLabelStyle={{color: blue300, height:'80%'}}
                                    fullWidth={true}
                                    onChange={(e, newValue) => {
                                        const phone = newValue;
                                        if (phone === '')
                                            this.setState({new_phone: phone, new_phone_err: '手机号不可为空'});
                                        else if(/^13[0-9]{1}[0-9]{8}|15[0-9]{1}[0-9]{8}|18[0-9]{1}[0-9]{8}$/.test(phone) && phone.length == 11)
                                            this.setState({new_phone: phone, default_phone: phone, new_phone_err: ''});
                                        else
                                            this.setState({new_phone: phone, new_phone_err: '手机号格式错误！'});

                                        db.table('users').where({phone: phone}).first().then((res) => {
                                            if (res) {
                                                this.setState({new_phone: phone, new_phone_err: '手机号已被注册！'});
                                            }
                                        }).catch(e=>{
                                            console.log(e)
                                        })
                                    }}
                                />
                                <TextField
                                    hintText='输入邮箱地址'
                                    errorText={new_email_err}
                                    floatingLabelText='邮箱'
                                    defaultValue={default_email}
                                    floatingLabelStyle={{color: blue300}}
                                    fullWidth={true}
                                    onChange={(e, newValue) => {
                                        const email = newValue;
                                        if (email === '')
                                            this.setState({new_email: email, new_email_err: '邮箱地址不可为空'});
                                        else if(/\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/.test(email))
                                            this.setState({new_email: email, new_email_err: '', default_email : email});
                                        else
                                            this.setState({new_email: email, new_email_err: '邮箱格式错误！'});
                                    }}
                                />
                                <TextField
                                    hintText='输入通讯住址'
                                    defaultValue={default_address}
                                    errorText={new_address_err}
                                    floatingLabelText='通讯地址'
                                    floatingLabelStyle={{color: blue300}}
                                    fullWidth={true}
                                    onChange={(e, newValue) => {
                                        const addr = newValue;
                                        if (addr === '')
                                            this.setState({new_address: addr, new_address_err: '通讯地址不可为空'});
                                        else
                                            this.setState({new_address: addr, default_address: addr, new_address_err: ''});
                                    }}
                                />
                                <TextField
                                    hintText='输入工作单位名称'
                                    errorText={new_unit_err}
                                    defaultValue={default_unit}
                                    floatingLabelText='工作单位'
                                    floatingLabelStyle={{color: blue300}}
                                    fullWidth={true}
                                    onChange={(e, newValue) => {
                                        const unit = newValue;
                                        if (unit === '')
                                            this.setState({new_unit: unit, new_unit_err: '工作单位不可为空'});
                                        else
                                            this.setState({new_unit: unit, default_unit: unit, new_unit_err: ''});
                                    }}
                                />

                                {this.renderStepActions(0)}
                            </StepContent>
                        </Step>
                        <Step>
                            <StepLabel>{'获取私钥和证书'}</StepLabel>
                            <StepContent>
                                <ol>
                                    <li>您可以生成新的私钥文件及对应的证书文件</li>
                                    <li>您也可以导入已有的私钥文件及其对应的证书文件</li>
                                </ol>
                                <RadioButtonGroup name='keypair-gen-way' defaultSelected={new_not_import}
                                                  onChange={(err, value) => {
                                                      this.setState({new_not_import: value});
                                                      if(value){
                                                          this.setState({import_prv_key_file_name:'',import_cert_file_name:'',
                                                              import_prv_key_b2s:'',import_cert_b2s:''});
                                                      }
                                                  }}>
                                    <RadioButton value={true} label='新建'/>
                                    <RadioButton value={false} label='导入'/>
                                </RadioButtonGroup>
                                <br/>
                                <Divider style={{marginTop: '-1%', marginLeft: '2%', marginRight:'2%',border: '0.02px dashed'}}/>
                                <br/>
                                {new_not_import?
                                    <div>
                                        输入密码以保护用户私钥
                                        <TextField
                                            hintText='输入密码'
                                            errorText={new_pass1_err}
                                            floatingLabelText='请牢记密码'
                                            floatingLabelStyle={{color: blue300}}
                                            fullWidth={true}
                                            type='password'
                                            onChange={(e, newValue) => {
                                                const pass = newValue;
                                                if (pass === '')
                                                    this.setState({new_pass1: pass, new_pass1_err: '密码不可为空'});
                                                else if( /^[A-Za-z0-9]{6,20}$/.test(pass)){
                                                    this.setState({new_pass1: pass, new_pass1_err: ''});
                                                    if (new_pass2 != '' && new_pass2 != pass)
                                                        this.setState({new_pass2_err: '密码不一致'});
                                                    else
                                                        this.setState({new_pass2_err: ''});

                                                }else {
                                                    this.setState({new_pass1: pass, new_pass1_err: '密码规则：6-20位字母或数字组合'})
                                                }
                                            }}
                                        /><br/>
                                        <TextField
                                            hintText='再次输入密码'
                                            errorText={new_pass2_err}
                                            floatingLabelText='确认密码'
                                            floatingLabelStyle={{color: blue300}}
                                            fullWidth={true}
                                            type='password'
                                            onChange={(e, newValue) => {
                                                const pass = newValue;
                                                if (pass != new_pass1)
                                                    this.setState({new_pass2: pass, new_pass2_err: '密码不一致'});
                                                else
                                                    this.setState({new_pass2: pass, new_pass2_err: ''});
                                            }}
                                        />
                                    </div>
                                    :
                                    <div>
                                        导入已有私钥文件及对应证书文件
                                        <div id='import_form'>
                                            <label>私钥：</label>
                                            <DropZone style={{
                                                width: 'auto', height: 'auto', display: 'inline-block', position: 'absolute',
                                                marginTop: -8, marginLeft: 10, marginRight: 10, border: import_prvkey_border_style
                                            }} accept='.prvkey,.pkcs8'
                                                      multiple={false}
                                                      onDrop={this.onDropPrvKeyFile.bind(this)}
                                            >
                                                <div
                                                    className='import_hint'>{import_prv_key_file_name != '' ? '已选择文件：' + import_prv_key_file_name : '单击此处选择文件'}</div>
                                            </DropZone>
                                        </div>
                                        <div id='import_form'>
                                            <label>证书：</label>
                                            <DropZone style={{
                                                width: 'auto', height: 'auto', display: 'inline-block', position: 'absolute',
                                                marginTop: -8, marginLeft: 10, marginRight: 10, border: import_cert_border_style
                                            }} accept='.cert,.cer'
                                                      multiple={false}
                                                      onDrop={this.onDropCertFile.bind(this)}
                                            >
                                                <div
                                                    className='import_hint'>{import_cert_file_name != '' ? '已选择文件：' + import_cert_file_name : '单击此处选择文件'}</div>
                                            </DropZone>
                                        </div>
                                    </div>

                                }
                                <br/>
                                {this.renderStepActions(1)}
                            </StepContent>
                        </Step>
                        <Step>
                            <StepLabel>账户生成</StepLabel>
                            <StepContent>
                                <p>
                                    注意：<br/>
                                    1、注册完成后，若您的证书未被repchain节点管理员认证通过，需要您下载证书且提供证书文件，并向某个节点管理员发起认证请求。<br/>
                                    2、如果导入密钥是Keytool的无密码的私钥，用户创建成功后初始密码为手机号，请尽快登录系统修改密码！
                                </p>
                                {this.renderStepActions(2)}
                            </StepContent>
                        </Step>
                    </Stepper>

                </Paper>
            </div>
        );
    }
}

AccountRegister.childContextTypes = {
    muiTheme: React.PropTypes.object.isRequired,
};